home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / unix / tkUnixNotify.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  21.3 KB  |  833 lines

  1. /* 
  2.  * tkUnixNotify.c --
  3.  *
  4.  *    This file provides the platform specific event detection
  5.  *    facilities used by the Tk event routines.  The procedures in
  6.  *    this file comprise the notifier interface and contain unix
  7.  *    specific file and timer handling code.
  8.  *
  9.  * Copyright (c) 1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  */
  14.  
  15. static char sccsid[] = "@(#) tkUnixNotify.c 1.22 95/10/03 13:51:51";
  16.  
  17. #include "tkPort.h"
  18. #include "tkInt.h"
  19. #include <signal.h>
  20.  
  21. /*
  22.  * The information below is used to provide read, write, and
  23.  * exception masks to select during calls to Tk_DoOneEvent.
  24.  */
  25.  
  26. static fd_mask ready[3*MASK_SIZE];
  27.                 /* Masks passed to select and modified
  28.                  * by kernel to indicate which files are
  29.                  * actually ready. */
  30. static fd_mask check[3*MASK_SIZE];
  31.                 /* Current set of masks, built up by
  32.                  * Tk_NotifyFile and Tk_NotifyDisplay,
  33.                  * that reflects what files we should wait
  34.                  * for in the next select. */
  35. static int numFdBits = 0;    /* Number of valid bits in mask
  36.                  * arrays (this value is passed
  37.                  * to select).  This value is only a high
  38.                  * water mark as long as at least one display
  39.                  * is registered.  If there are no displays,
  40.                  * then it is recomputed at the end of each
  41.                  * call to Tk_DoOneEvent. */
  42.  
  43. /*
  44.  * For each display that Tk has called Tk_NotifyDisplay, there is one
  45.  * record of the following type, chained together in a list.
  46.  */
  47.  
  48. typedef struct DisplayList {
  49.     Display *display;        /* Display from which events may arrive. */
  50.     fd_mask *readPtr;        /* Pointer to word in ready array
  51.                  * for this display's read mask bit. */
  52.     fd_mask *checkReadPtr;    /* Pointer to word in check array
  53.                  * for this display's read mask bit. */
  54.     fd_mask bitSelect;        /* Value to AND with *readPtr etc. to
  55.                  * select just this file's bit. */
  56.     struct DisplayList *nextPtr;
  57.                 /* Next display in list, nor NULL for
  58.                  * end of queue. */
  59. } DisplayList;
  60.  
  61. static DisplayList *firstDisplayPtr;
  62.                 /* First display in list of registered */
  63.                 /* displays. */
  64.  
  65. /*
  66.  * The notifier has at most one pending timer.  The next scheduled timer
  67.  * event is recorded in the pendingTimeout structure.  The
  68.  * pendingTimeoutPtr is set to refer to pendingTimeout by Tk_NotifyTimer.
  69.  * Once the timer fires, Tk_DoOneEvent resets the pointer to NULL.
  70.  */
  71.  
  72. static Tk_Time *pendingTimeoutPtr;
  73.                 /* Points to current timer value. */
  74. static Tk_Time pendingTimeout;    /* Time when timer should fire. */
  75.  
  76. /*
  77.  * Prototypes for procedures referenced only in this file:
  78.  */
  79.  
  80. static int        ServiceDisplay _ANSI_ARGS_((Display *display));
  81. static void        RefreshFdBits _ANSI_ARGS_((void));
  82.  
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * ServiceDisplay --
  87.  *
  88.  *    This function is called by Tk_DoOneEvent whenever the notifier
  89.  *    detects that the Display's fd is readable.  It is responsible
  90.  *    for retrieving and queueing any pending X events.
  91.  *
  92.  * Results:
  93.  *    The return value is 1 if the procedure found an event to
  94.  *    queue.  If no events were found, then 0 is returned.
  95.  *
  96.  * Side effects:
  97.  *    Passes all pending X events to Tk_QueueEvent.
  98.  *
  99.  *----------------------------------------------------------------------
  100.  */
  101.  
  102. static int
  103. ServiceDisplay(display)
  104.     Display *display;        /* Display to service. */
  105. {
  106.     Tk_Event event;
  107.     int numFound;
  108.  
  109.     /*
  110.      * We should not need to do a flush of the output queues before
  111.      * calling XEventsQueued because it should have been done before
  112.      * we called select in Tk_DoOneEvent.
  113.      */
  114.     
  115.     numFound = XEventsQueued(display, QueuedAfterReading);
  116.     if (numFound == 0) {
  117.  
  118.     /*
  119.      * Things are very tricky if there aren't any events readable
  120.      * at this point (after all, there was supposedly data
  121.      * available on the connection).  A couple of things could
  122.      * have occurred:
  123.      * 
  124.      * One possibility is that there were only error events in the
  125.      * input from the server.  If this happens, we should return
  126.      * (we don't want to go to sleep in XNextEvent below, since
  127.      * this would block out other sources of input to the
  128.      * process).
  129.      *
  130.      * Another possibility is that our connection to the server
  131.      * has been closed.  This will not necessarily be detected in
  132.      * XEventsQueued (!!), so if we just return then there will be
  133.      * an infinite loop.  To detect such an error, generate a NoOp
  134.      * protocol request to exercise the connection to the server,
  135.      * then return.  However, must disable SIGPIPE while sending
  136.      * the request, or else the process will die from the signal
  137.      * and won't invoke the X error function to print a nice (?!)
  138.      * message.
  139.      */
  140.  
  141.     void (*oldHandler)();
  142.  
  143.     oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);
  144.     XNoOp(display);
  145.     XFlush(display);
  146.     (void) signal(SIGPIPE, oldHandler);
  147.     return 0;
  148.     }
  149.  
  150.     /*
  151.      * Transfer events from the X event queue to the Tk event queue.
  152.      */
  153.     
  154.     event.type = TK_WINDOW_EVENTS;
  155.     while (numFound > 0) {
  156.     XNextEvent(display, &event.window.event);
  157.     Tk_QueueEvent(&event, TK_QUEUE_TAIL);
  158.     numFound--;
  159.     }
  160.     return 1;
  161. }
  162.  
  163. /*
  164.  *----------------------------------------------------------------------
  165.  *
  166.  * Tk_NotifyFile --
  167.  *
  168.  *    Arrange for Tk_QueueEvent to be called the next time a given
  169.  *    I/O channel becomes readable or writable.  This is a one-shot
  170.  *    event.
  171.  *
  172.  * Results:
  173.  *    None.
  174.  *
  175.  * Side effects:
  176.  *    The notifier will generate a file event when the I/O channel
  177.  *    given by fd next becomes ready in the way indicated by mask.
  178.  *    If fd is already registered then the old mask will be replaced
  179.  *    with the new one.  Once the event is sent, the notifier will
  180.  *    not send any more events about the fd until the next call to
  181.  *    Tk_NotifyFile. 
  182.  *
  183.  *----------------------------------------------------------------------
  184.  */
  185.  
  186. void
  187. Tk_NotifyFile(fd, mask)
  188.     int fd;            /* Integer identifier for a stream. */
  189.     int mask;            /* OR'ed combination of TK_READABLE,
  190.                  * TK_WRITABLE, and TK_EXCEPTION:
  191.                  * indicates conditions under which a
  192.                  * new event should be queued. */
  193. {
  194.     int index;
  195.     fd_mask bitSelect;
  196.     
  197.     if (fd >= FD_SETSIZE) {
  198.     panic("Tk_NotifyFile can't handle file id %d", fd);
  199.     }
  200.  
  201.     /*
  202.      * Make sure the appropriate check bits are set for the specified file
  203.      * descriptor.  
  204.      */
  205.  
  206.     index = fd/(NBBY*sizeof(fd_mask));
  207.     bitSelect = 1 << (fd%(NBBY*sizeof(fd_mask)));
  208.     if (mask & TK_READABLE) {
  209.     check[index] |= bitSelect;
  210.     } else {
  211.     check[index] &= ~bitSelect;
  212.     }
  213.     if (mask & TK_WRITABLE) {
  214.     check[index+MASK_SIZE] |= bitSelect;
  215.     } else {
  216.     check[index+MASK_SIZE] &= ~bitSelect;
  217.     }
  218.     if (mask & TK_EXCEPTION) {
  219.     check[index+2*MASK_SIZE] |= bitSelect;
  220.     } else {
  221.     check[index+2*MASK_SIZE] &= ~bitSelect;
  222.     }
  223.  
  224.     if (numFdBits <= fd) {
  225.     numFdBits = fd+1;
  226.     }
  227. }
  228.  
  229. /*
  230.  *----------------------------------------------------------------------
  231.  *
  232.  * Tk_IgnoreFile --
  233.  *
  234.  *    Cancel an outstanding file event request.
  235.  *
  236.  * Results:
  237.  *    None.
  238.  *
  239.  * Side effects:
  240.  *    The notifier will stop looking for events on the I/O channel
  241.  *    given by fd. 
  242.  *
  243.  *----------------------------------------------------------------------
  244.  */
  245.  
  246. void
  247. Tk_IgnoreFile(fd)
  248.     int fd;            /* Integer identifier for a stream. */
  249. {
  250.     int index;
  251.     fd_mask bitSelect;
  252.  
  253.     /*
  254.      * Turn off check bits for the specified file.
  255.      */
  256.  
  257.     index = fd/(NBBY*sizeof(fd_mask));
  258.     bitSelect = 1 << (fd%(NBBY*sizeof(fd_mask)));
  259.     check[index] &= ~bitSelect;
  260.     check[index+MASK_SIZE] &= ~bitSelect;
  261.     check[index+2*MASK_SIZE] &= ~bitSelect;
  262.  
  263.     /*
  264.      * If this fd was at the high water mark and there is a chance
  265.      * that it was the last fd, then recompute the numFdBits.
  266.      */
  267.  
  268.     if ((firstDisplayPtr != NULL) && (fd == (numFdBits-1))) {
  269.     RefreshFdBits();
  270.     }
  271. }
  272.  
  273. /*
  274.  *----------------------------------------------------------------------
  275.  *
  276.  * Tk_NotifyDisplay --
  277.  *
  278.  *    Arrange for events to be generated for a particular display.
  279.  *
  280.  * Results:
  281.  *    None.
  282.  *
  283.  * Side effects:
  284.  *    From now on, all window system events directed at display will
  285.  *    be passed to Tk_QueueEvent.
  286.  *
  287.  *----------------------------------------------------------------------
  288.  */
  289.  
  290. void
  291. Tk_NotifyDisplay(display)
  292.     Display *display;        /* Display for which events should be
  293.                  * generated. */
  294. {
  295.     int index, fd;
  296.     DisplayList *displayPtr;
  297.  
  298.     /*
  299.      * Ignore duplicate displays.
  300.      */
  301.  
  302.     for (displayPtr = firstDisplayPtr; displayPtr != NULL;
  303.         displayPtr = displayPtr->nextPtr) {
  304.     if (displayPtr->display == display) {
  305.         return;
  306.     }
  307.     }
  308.  
  309.     /*
  310.      * Add the display to the display list.
  311.      */
  312.  
  313.     fd = ConnectionNumber(display);
  314.     displayPtr = (DisplayList *) ckalloc(sizeof(DisplayList));
  315.     displayPtr->display = display;
  316.     index = fd/(NBBY*sizeof(fd_mask));
  317.     displayPtr->readPtr = &ready[index];
  318.     displayPtr->checkReadPtr = &check[index];
  319.     displayPtr->bitSelect = 1 << (fd%(NBBY*sizeof(fd_mask)));
  320.     displayPtr->nextPtr = firstDisplayPtr;
  321.     firstDisplayPtr = displayPtr;
  322.  
  323.     check[index] |= displayPtr->bitSelect;
  324.  
  325.     if (numFdBits <= fd) {
  326.     numFdBits = fd+1;
  327.     }
  328. }
  329.  
  330. /*
  331.  *----------------------------------------------------------------------
  332.  *
  333.  * Tk_IgnoreDisplay --
  334.  *
  335.  *    Arrange for events to no longer be delivered for a particular
  336.  *    display.
  337.  *
  338.  * Results:
  339.  *    None.
  340.  *
  341.  * Side effects:
  342.  *    From now on, the notifier will not generate events for a
  343.  *    particular display.
  344.  *
  345.  *----------------------------------------------------------------------
  346.  */
  347.  
  348. void
  349. Tk_IgnoreDisplay(display)
  350.     Display *display;        /* Display for which events should not
  351.                  * be generated. */
  352. {
  353.     int index, fd;
  354.     DisplayList *displayPtr, *prevPtr;
  355.     fd_mask bitSelect;
  356.  
  357.     for (displayPtr = firstDisplayPtr, prevPtr = NULL; displayPtr != NULL;
  358.         prevPtr = displayPtr, displayPtr = displayPtr->nextPtr) {
  359.     if (displayPtr->display != display) {
  360.         continue;
  361.     }
  362.     if (prevPtr == NULL) {
  363.         firstDisplayPtr = displayPtr->nextPtr;
  364.     } else {
  365.         prevPtr->nextPtr = displayPtr->nextPtr;
  366.     }
  367.     fd = ConnectionNumber(display);
  368.     index = fd/(NBBY*sizeof(fd_mask));
  369.     bitSelect = 1 << (fd%(NBBY*sizeof(fd_mask)));
  370.     check[index] &= ~bitSelect;
  371.     ckfree((char *) displayPtr);
  372.  
  373.     /*
  374.      * If this fd was at the high water mark and there is a chance
  375.      * that it was the last fd, then recompute the numFdBits.
  376.      */
  377.  
  378.     if ((firstDisplayPtr != NULL) && (fd == (numFdBits-1))) {
  379.         RefreshFdBits();
  380.     }
  381.  
  382.     return;
  383.     }
  384. }
  385.  
  386. /*
  387.  *----------------------------------------------------------------------
  388.  *
  389.  * Tk_NotifyTimer --
  390.  *
  391.  *    Arrange for an event to be generated at a particular time in
  392.  *    the future.  This is a one-shot event.
  393.  *
  394.  * Results:
  395.  *    None.
  396.  *
  397.  * Side effects:
  398.  *    When the time specified by timeout is reached, a timer event
  399.  *    will be passed to Tk_QueueEvent.  There is only one
  400.  *    outstanding timer, so if the previous timer has not expired,
  401.  *    it will be replaced with the current timeout value.  Only one
  402.  *    timer event will be generated after the timer expires until
  403.  *    the next call to Tk_NotifyTimer.
  404.  *
  405.  *----------------------------------------------------------------------
  406.  */
  407.  
  408. void
  409. Tk_NotifyTimer(time)
  410.     Tk_Time *time;        /* Absolute time when the notifier should
  411.                  * generate a timer event. */
  412. {
  413.     pendingTimeoutPtr = &pendingTimeout;
  414.     pendingTimeout = *time;
  415. }
  416.  
  417. /*
  418.  *----------------------------------------------------------------------
  419.  *
  420.  * Tk_DoOneEvent --
  421.  *
  422.  *    Process a single event of some sort.  If there's no work to
  423.  *    do, wait for an event to occur, then process it.
  424.  *
  425.  * Results:
  426.  *    The return value is 1 if the procedure actually found an event
  427.  *    to process.  If no processing occurred, then 0 is returned.
  428.  *    The caller should invoke Tk_DoOneEvent repeatedly until it
  429.  *    returns 0 to insure that all events have been processed.
  430.  *
  431.  * Side effects:
  432.  *    May delay execution of process while waiting for an event,
  433.  *    unless TK_DONT_WAIT is set in the flags argument.
  434.  *    Tk_ServiceEvent will be called at most once.  If no queued
  435.  *    events were processed, then the procedure checks for new
  436.  *    events.  If TK_DONT_WAIT is set or Tk has called
  437.  *    Tk_NotifyIdle since the last time Tk_ServiceIdle was called,
  438.  *    then Tk_DoOneEvent will only poll for events, otherwise it
  439.  *    blocks until the next event occurs.  All detected events will
  440.  *    be queued.  If no events are detected, and Tk has called
  441.  *    Tk_NotifyIdle, then Tk_ServiceIdle will be called.
  442.  *
  443.  *----------------------------------------------------------------------
  444.  */
  445.  
  446. int
  447. Tk_DoOneEvent(flags)
  448.     int flags;            /* Miscellaneous flag values:  may be any
  449.                  * combination of TK_DONT_WAIT,
  450.                  * TK_WINDOW_EVENTS, TK_FILE_EVENTS,
  451.                  * TK_TIMER_EVENTS, and TK_IDLE_EVENTS. */
  452. {
  453.     DisplayList *displayPtr;
  454.     struct timeval curTime, timeout, *timeoutPtr;
  455.     Tk_Event event;
  456.     fd_mask fdmask, bitSelect;
  457.     int index, numFound;
  458.     int foundEvent = 0;
  459.     int dontLoop;        /* Avoid reentering select if set to 1. */
  460.  
  461.     /*
  462.      * No event flags is equivalent to TK_ALL_EVENTS.
  463.      */
  464.     
  465.     if ((flags & TK_ALL_EVENTS) == 0) {
  466.     flags |= TK_ALL_EVENTS;
  467.     }
  468.  
  469.     dontLoop = (flags & TK_DONT_WAIT);
  470.  
  471.     /*
  472.      * Look for events until we find something to do, or no other events
  473.      * are possible.
  474.      */
  475.  
  476.     do {
  477.  
  478.     /*
  479.      * The first thing we do is to service any asynchronous event
  480.      * handlers.
  481.      */
  482.     
  483.     if (Tcl_AsyncReady()) {
  484.         (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
  485.         return 1;
  486.     }
  487.  
  488.     /*
  489.      * Ask Tk to service a queued event.  If Tk does not handle any events,
  490.      * then we should look for new events.
  491.      */
  492.  
  493.     if (Tk_ServiceEvent(flags)) {
  494.         return 1;        /* Tk serviced an event so we're done. */
  495.     }
  496.  
  497.     /*
  498.      * Skip to the idle handlers if that is all we are doing.  Since
  499.      * nothing else can happen, we set dontLoop to 1.
  500.      */
  501.  
  502.     if ((flags & TK_ALL_EVENTS) == TK_IDLE_EVENTS) {
  503.         dontLoop = 1;
  504.         goto doIdle;
  505.     }
  506.  
  507.     /*
  508.      * First we need to check for X events which are already queued.
  509.      */
  510.  
  511.     if ((flags & TK_WINDOW_EVENTS)) {
  512.         for (displayPtr = firstDisplayPtr; displayPtr != NULL;
  513.             displayPtr = displayPtr->nextPtr) {
  514.         XFlush(displayPtr->display);
  515.         if (XQLength(displayPtr->display) > 0) {
  516.             if (ServiceDisplay(displayPtr->display)) {
  517.             foundEvent = 1;
  518.             }
  519.         }
  520.         }
  521.     }
  522.  
  523.     /*
  524.      * Load the select mask from the current check mask.
  525.      */
  526.  
  527.     memcpy((VOID *) ready, (VOID *) check, 3*MASK_SIZE*sizeof(fd_mask));
  528.  
  529.     /*
  530.      * Compute the current timeout value.  If we have already detected an
  531.      * event, if idle tasks are pending or if TK_DONT_WAIT is set, then we
  532.      * should poll.  If a timer is pending, then we should compute the
  533.      * remaining time.  Otherwise, we block.
  534.      */
  535.  
  536.     if (foundEvent
  537.         || (flags & TK_DONT_WAIT)
  538.         || ((flags & TK_IDLE_EVENTS) && Tk_IdlePending())) {
  539.         timeout.tv_sec = 0;
  540.         timeout.tv_usec = 0;
  541.         timeoutPtr = &timeout;
  542.     } else if ((pendingTimeoutPtr != NULL) && (flags & TK_TIMER_EVENTS)) {
  543.         (void) gettimeofday(&curTime, (struct timezone *) NULL);
  544.  
  545.         /*
  546.          * Check to see if the timer has expired.
  547.          */
  548.  
  549.         if ((pendingTimeoutPtr->sec < curTime.tv_sec)
  550.             || ((pendingTimeoutPtr->sec == curTime.tv_sec)
  551.                 &&  (pendingTimeoutPtr->usec < curTime.tv_usec))) {
  552.         timeout.tv_sec = 0;
  553.         timeout.tv_usec = 0;
  554.         } else {
  555.         timeout.tv_sec = pendingTimeoutPtr->sec - curTime.tv_sec;
  556.         timeout.tv_usec = pendingTimeoutPtr->usec - curTime.tv_usec;
  557.         if (timeout.tv_usec < 0) {
  558.             timeout.tv_sec -= 1;
  559.             timeout.tv_usec += 1000000;
  560.         }
  561.         }
  562.         timeoutPtr = &timeout;
  563.     } else {
  564.         timeoutPtr = NULL;
  565.     }
  566.  
  567.     /*
  568.      * If no events could be detected, return immediately to
  569.      * avoid blocking forever.
  570.      */
  571.     
  572.     if ((timeoutPtr == NULL) && (numFdBits == 0)) {
  573.         return 0;
  574.     }
  575.  
  576.     /*
  577.      * Wait until an event occurs or the timer expires.
  578.      */
  579.  
  580.     numFound = select(numFdBits, (SELECT_MASK *) &ready[0],
  581.         (SELECT_MASK *) &ready[MASK_SIZE],
  582.         (SELECT_MASK *) &ready[2*MASK_SIZE], timeoutPtr);
  583.  
  584.     /*
  585.      * Some systems don't clear the masks after an error, so
  586.      * we have to do it here.
  587.      */
  588.  
  589.     if (numFound == -1) {
  590.         memset((VOID *) ready, 0, 3*MASK_SIZE*sizeof(fd_mask));
  591.     }
  592.  
  593.     /*
  594.      * Check to see if the timer has expired.
  595.      */
  596.  
  597.     if ((pendingTimeoutPtr != NULL) && (flags & TK_TIMER_EVENTS)) {
  598.         (void) gettimeofday(&curTime, (struct timezone *) NULL);
  599.         if ((pendingTimeoutPtr->sec < curTime.tv_sec)
  600.             || ((pendingTimeoutPtr->sec == curTime.tv_sec)
  601.                 &&  (pendingTimeoutPtr->usec < curTime.tv_usec))) {
  602.         pendingTimeoutPtr = NULL;
  603.  
  604.         /*
  605.          * Generate timer event.
  606.          */
  607.  
  608.         foundEvent = 1;
  609.         event.type = TK_TIMER_EVENTS;
  610.         event.timer.time.sec = curTime.tv_sec;
  611.         event.timer.time.usec = curTime.tv_usec;
  612.         Tk_QueueEvent(&event, TK_QUEUE_TAIL);
  613.         }
  614.     }
  615.  
  616.     /*
  617.      * Check for window system events.  Once a display has been serviced,
  618.      * it is removed from the ready mask, so we don't generate a file event
  619.      * for it.
  620.      */
  621.  
  622.     for (displayPtr = firstDisplayPtr; displayPtr != NULL;
  623.                        displayPtr = displayPtr->nextPtr) {
  624.         if (*displayPtr->readPtr & displayPtr->bitSelect) {
  625.         if (ServiceDisplay(displayPtr->display)) {
  626.             foundEvent = 1;
  627.         }
  628.         numFound--;
  629.         *displayPtr->readPtr &= ~(displayPtr->bitSelect);
  630.         }
  631.     }
  632.  
  633.     /*
  634.      * Check for file events.  We iterate over the ready fd_masks looking
  635.      * for a mask with any bits set.  By or'ing the read, write, and
  636.      * exception masks together, we can make a single pass through the file
  637.      * descriptors.  If any event occured on a file, we need to queue a
  638.      * file event with the appropriate file descriptor and event mask, and
  639.      * then clear all of the check bits for that file.
  640.      */
  641.     
  642.     if (numFound > 0) {
  643.         foundEvent = 1;
  644.         event.type = TK_FILE_EVENTS;
  645.         index = -1;
  646.         bitSelect = 0;
  647.         event.file.fd = 0;
  648.         fdmask = 0;
  649.  
  650.         /*
  651.          * Each time through the loop we shift bitSelect.  When we
  652.          * have tested each bit in the current mask, bitSelect becomes
  653.          * zero, so we know to continue with the next mask in the set.
  654.          */
  655.     
  656.         while (numFound > 0) {
  657.         if (!bitSelect) {    /* check for wrap-around */
  658.             if (event.file.fd >= numFdBits) {
  659.             /*
  660.              * Somehow there aren't as many files ready as numFound
  661.              * suggests.  Either select lied to us or there is a
  662.              * reentrancy problem here.
  663.              */
  664.  
  665.             panic("Tk_DoOneEvent got bogus count from select");
  666.             }
  667.             bitSelect = 1;
  668.             index++;
  669.             fdmask = ready[index] | ready[index+MASK_SIZE]
  670.             | ready[index+2*MASK_SIZE];
  671.         }
  672.         if (fdmask & bitSelect) {
  673.             numFound--;
  674.             event.file.mask = 0;
  675.             if (ready[index] & bitSelect) {
  676.             event.file.mask |= TK_READABLE;
  677.             }
  678.             if (ready[index+MASK_SIZE] & bitSelect) {
  679.             event.file.mask |= TK_WRITABLE;
  680.             }
  681.             if (ready[index+2*MASK_SIZE] & bitSelect) {
  682.             event.file.mask |= TK_EXCEPTION;
  683.             }
  684.             Tk_QueueEvent(&event, TK_QUEUE_TAIL);
  685.             check[index] &= ~bitSelect;
  686.             check[index+MASK_SIZE] &= ~bitSelect;
  687.             check[index+2*MASK_SIZE] &= ~bitSelect;
  688.         }
  689.         bitSelect <<= 1;
  690.         event.file.fd++;
  691.         }
  692.  
  693.         /*
  694.          * If there are no displays currently registered, then we need to
  695.          * recompute numFdBits since some bits have been cleared and we may
  696.          * block the next time through.
  697.          */
  698.  
  699.         if (firstDisplayPtr == NULL) {
  700.         RefreshFdBits();
  701.         }
  702.     }
  703.         
  704.     /*
  705.      * If no other events were generated, then we should try to 
  706.      * service pending idle handlers.
  707.      */
  708.  
  709.     doIdle:
  710.     if (!foundEvent && (flags & TK_IDLE_EVENTS)) {
  711.         foundEvent = Tk_ServiceIdle();
  712.     }
  713.  
  714.     } while (!foundEvent && !dontLoop);
  715.  
  716.     /*
  717.      * No other events can be detected at this point.
  718.      */
  719.  
  720.     return foundEvent;
  721. }
  722.  
  723. /*
  724.  *----------------------------------------------------------------------
  725.  *
  726.  * Tk_Sleep --
  727.  *
  728.  *    Delay execution for the specified number of milliseconds.
  729.  *
  730.  * Results:
  731.  *    None.
  732.  *
  733.  * Side effects:
  734.  *    Time passes.
  735.  *
  736.  *----------------------------------------------------------------------
  737.  */
  738.  
  739. void
  740. Tk_Sleep(ms)
  741.     int ms;            /* Number of milliseconds to sleep. */
  742. {
  743.     static struct timeval delay;
  744.  
  745.     delay.tv_sec = ms/1000;
  746.     delay.tv_usec = (ms%1000)*1000;
  747.     (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
  748.         (SELECT_MASK *) 0, &delay);
  749. }
  750.  
  751. /*
  752.  *--------------------------------------------------------------
  753.  *
  754.  * Tk_MainLoop --
  755.  *
  756.  *    Call Tk_DoOneEvent over and over again in an infinite
  757.  *    loop as long as there exist any main windows.
  758.  *
  759.  * Results:
  760.  *    None.
  761.  *
  762.  * Side effects:
  763.  *    Arbitrary;  depends on handlers for events.
  764.  *
  765.  *--------------------------------------------------------------
  766.  */
  767.  
  768. void
  769. Tk_MainLoop()
  770. {
  771.     while (Tk_GetNumMainWindows() > 0) {
  772.     Tk_DoOneEvent(0);
  773.     }
  774. }
  775.  
  776. /*
  777.  *----------------------------------------------------------------------
  778.  *
  779.  * RefreshFdBits --
  780.  *
  781.  *    This function finds the largest currently registered
  782.  *    file descriptor from the check mask.
  783.  *
  784.  * Results:
  785.  *    None.
  786.  *
  787.  * Side effects:
  788.  *    Updates the numFdBits static variable.
  789.  *
  790.  *----------------------------------------------------------------------
  791.  */
  792.  
  793. static void
  794. RefreshFdBits()
  795. {
  796.     int limit, index;
  797.     fd_mask fdmask;
  798.  
  799.     /*
  800.      * We start by finding the largest element of the check array that
  801.      * contains at least one set bit.  We start the search with the
  802.      * last known maximum index value.
  803.      */
  804.  
  805.     limit = (numFdBits / (NBBY*sizeof(fd_mask)));
  806.     numFdBits = 0;
  807.     fdmask = 0;
  808.     for (index = limit; (index >= 0); index--) {
  809.     fdmask = check[index] | check[index+MASK_SIZE]
  810.         | check[index+2*MASK_SIZE];
  811.     if (fdmask) {
  812.         break;
  813.     }
  814.     }
  815.  
  816.     /*
  817.      * Now that we have the biggest mask, we need to find the most
  818.      * significant bit.
  819.      */
  820.  
  821.     if (fdmask) {
  822.     int offset;
  823.     numFdBits = index*NBBY*sizeof(fd_mask);
  824.     for (offset = 0; ; offset++) {
  825.         fdmask &= ~(1<<offset);
  826.         if (!fdmask) {
  827.         break;
  828.         }
  829.     }
  830.     numFdBits += (offset+1);
  831.     }
  832. }
  833.